package order

import (
	"context"
	"strings"
	"time"

	"mall/common/globalkey"
	"mall/common/moneyx"
	"mall/common/uniqueidx"
	"mall/service/backend/common/errorx"
	"mall/service/backend/common/i18n"
	"mall/service/order/model"
	"mall/service/order/rpc/internal/svc"
	"mall/service/order/rpc/internal/utils/errorhandler"
	"mall/service/order/rpc/types/order"

	"github.com/volatiletech/null/v8"
	"github.com/zeromicro/go-zero/core/logx"
)

type BackendUpdateOrderLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewBackendUpdateOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BackendUpdateOrderLogic {
	return &BackendUpdateOrderLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *BackendUpdateOrderLogic) BackendUpdateOrder(in *order.BackendUpdateOrderReq) (*order.BaseResp, error) {
	logx.Infof("BackendUpdateOrderReq : %+v ", in)

	tx, err := l.svcCtx.DB.BeginTx(l.ctx, nil)
	if err != nil {
		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
	}

	if len(in.Ids) > 0 { // 批量修改状态
		now := time.Now()
		for _, id := range in.Ids {
			if id > 0 && in.TradeState != nil {
				trade, err := l.svcCtx.Order.FindOneNoCache(l.ctx, tx, id)
				if err != nil {
					tx.Rollback()
					return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
				}

				trade.TradeState = uint16(*in.TradeState)
				trade.UpdatedAt = now
				err = l.svcCtx.Order.Update(l.ctx, tx, trade, nil)
				if err != nil {
					tx.Rollback()
					return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
				}
			}
		}

		tx.Commit()

		return &order.BaseResp{
			Msg: i18n.UpdateSuccess,
		}, nil
	}

	if in.Id == nil || *in.Id == 0 {
		return nil, errorx.NewInvalidArgumentError(i18n.ValidationError)
	}

	if in.AdjustAmount == nil || len(*in.AdjustAmount) == 0 {
		return nil, errorx.NewInvalidArgumentError(i18n.ValidationError)
	}

	adjustAmount, err := moneyx.ParseAmount(strings.TrimSpace(*in.AdjustAmount))
	if err != nil {
		return nil, errorx.NewInvalidArgumentError(i18n.ValidationError)
	}

	id := *in.Id
	trade, err := l.svcCtx.Order.FindOneNoCache(l.ctx, tx, id)
	if err != nil {
		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
	}

	var opType uint8 = 1
	opName := "添加备注"
	opCode := "add memo"
	var memo string
	var status uint8 = 1
	var updatedBy uint64
	if in.SellerMemo != nil {
		memo = strings.TrimSpace(*in.SellerMemo)
	}
	if in.UpdatedBy != nil {
		updatedBy = *in.UpdatedBy
	}

	now := time.Now()
	rel := &model.OrderRel{}
	if adjustAmount > 0 { // 调整价格
		if adjustAmount >= int64(trade.RemainingAmount) {
			return nil, errorx.NewInvalidArgumentError(i18n.ValidationError)
		}

		if uint32(trade.TradeState) != globalkey.OrderTradeStateNotPay {
			return nil, errorx.NewInvalidArgumentError(i18n.ValidationError)
		}

		filterMap := make(map[string]map[string][]any)
		filterMap[model.OrderPaymentColumns.OrderID] = map[string][]any{
			"equalTo": {trade.ID},
		}
		list, _, err := l.svcCtx.Order.GetPaymentList(l.ctx, model.M{
			"orderBy":  model.OrderPaymentColumns.OrderPaymentID + " DESC",
			"pageSize": uint64(1),
		}, -1, filterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) == 0 {
			return nil, errorx.NewInvalidArgumentError(i18n.ValidationError)
		}

		payment := list[0]
		if payment.Type == uint8(globalkey.PaymentTypeWeChatPay) {
			// 微信支付
			sn := uniqueidx.GenSn(uniqueidx.SN_PREFIX_THIRD_PART_PAYMENT)
			rel.Payments = append(rel.Payments, &model.OrderPayment{
				No:     sn,
				Amount: trade.RemainingAmount - uint64(adjustAmount),
				Type:   uint8(globalkey.PaymentTypeWeChatPay),
				Name:   "微信支付",
				Code:   "WeChatPay",
				Status: uint8(globalkey.PaymentStatusNotPay),
				PaidAt: null.TimeFromPtr(nil),
			})
		}

		rel.Adjustments = append(rel.Adjustments, &model.OrderAdjustment{
			Amount:     adjustAmount,
			Memo:       memo,
			Status:     status,
			OperatedBy: updatedBy,
			OperatedAt: null.TimeFrom(now),
		})

		opType = 2
		opName = "下调价格:" + moneyx.FormatAmount(adjustAmount)
		opCode = "adjust amount"
		trade.AdjustAmount = trade.AdjustAmount + adjustAmount
		trade.ActualAmount = trade.ActualAmount - uint64(adjustAmount)
		trade.RemainingAmount = trade.RemainingAmount - uint64(adjustAmount)
	}
	trade.SellerMemo = memo
	rel.Logs = append(rel.Logs, &model.OrderOperateLog{
		TradeState: trade.TradeState,
		Type:       opType,
		Name:       opName,
		Code:       opCode,
		Status:     status,
		Memo:       memo,
		OperatedBy: uint64(updatedBy),
		OperatedAt: null.TimeFrom(now),
	})
	err = l.svcCtx.Order.Update(l.ctx, tx, trade, rel)
	if err != nil {
		tx.Rollback()
		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
	}

	tx.Commit()

	return &order.BaseResp{
		Msg: i18n.UpdateSuccess,
	}, nil
}
